import json
from dataclasses import dataclass
from typing import List, Dict, Optional


@dataclass
class StudentGrade:
    stu_name: str
    stu_code: str
    group_name: str
    exam_code: str
    exam_score: Optional[float] = None
    exam_grade: Optional[str] = None

    def to_dict(self):
        return {
            'stu_name': self.stu_name,
            'stu_code': self.stu_code,
            'group_name': self.group_name,
            'exam_code': self.exam_code,
            'exam_score': self.exam_score,
            'exam_grade': self.exam_grade
        }


@dataclass
class Grade:
    stu_code: str
    stu_name: str
    exam_code: str
    score: float
    grade: str
    rank: Optional[int] = None

    def to_dict(self):
        return {
            'stu_code': self.stu_code,
            'stu_name': self.stu_name,
            'exam_code': self.exam_code,
            'score': self.score,
            'grade': self.grade,
            'rank': self.rank
        }


@dataclass
class Student:
    name: str
    code: str
    grades: List[Grade] = None

    def __post_init__(self):
        if self.grades is None:
            self.grades = []

    def query_grade(self, exam_code: str) -> Optional[Grade]:
        return next((grade for grade in self.grades if grade.exam_code == exam_code), None)

    def add_grade(self, grade: Grade):
        self.grades.append(grade)


@dataclass
class Exam:
    code: str
    avg_score: float
    median_score: float
    pass_rate: float
    actual_num: int
    expected_num: int
    levels_item: Dict[str, List]
    top3: List
    bottom3: List

    def to_dict(self):
        return {
            'code': self.code,
            'avg_score': self.avg_score,
            'median_score': self.median_score,
            'pass_rate': self.pass_rate,
            'actual_num': self.actual_num,
            'expected_num': self.expected_num,
            'levels_item': self.levels_item,
            'top3': self.top3,
            'bottom3': self.bottom3
        }
